#include<iostream>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<cstring>
#include"Thread.hpp"
#include"err.hpp"


using namespace std;

class UdpClient
{
public:
  UdpClient(string serverIp,uint16_t serverPort)
    :_serverIp(serverIp)
    ,_serverPort(serverPort)
  {
    c = new Thread(1,send,this); 
    p = new Thread(2,rec,this);
  }

  void Start()
  {
    _socket = socket(AF_INET,SOCK_DGRAM,0);
    if(_socket == -1)
    {
      cerr << "create socket fail" << endl;
      exit(SOCKET_ERR);
    }
    cout << "create socket success" << endl;

    //明确server
    struct sockaddr_in peer;
    memset(&peer,0,sizeof(peer));
    peer.sin_family = AF_INET;
    peer.sin_port = htons(_serverPort);//主机序列转网络序列，修正大小端问题
    peer.sin_addr.s_addr = inet_addr(_serverIp.c_str());//该函数作用 1.将点分十进制字符串转为int 2.主机序列转为网络序列
 
    cout << "sin_family : " << AF_INET << " sin_port : " << peer.sin_port << " s._addr " << inet_addr(_serverIp.c_str()) << endl;

    c->run();
    p->run();
  }

  static void* send(void* args)
  {
    UdpClient* client = static_cast<UdpClient*>(args);
    while(true)
    {
      string buffer;
      getline(cin,buffer);

      struct sockaddr_in peer;
      memset(&peer,0,sizeof(peer));
      peer.sin_family = AF_INET;
      peer.sin_port = htons(client->_serverPort);//主机序列转网络序列，修正大小端问题
      peer.sin_addr.s_addr = inet_addr(client->_serverIp.c_str());//该函数作用 1.将点分十进制字符串转为int 2.主机序列转为网络序列
      
      sendto(client->_socket,buffer.c_str(),buffer.size(),0,(struct sockaddr*)&peer,sizeof(peer));//sento表示发送，这里的peer是用来明确发送给谁的
    }
  }

  static void* rec(void* args)
  {
    UdpClient* client = static_cast<UdpClient*>(args);
    while(true)
    {
      char str[1024];
      struct sockaddr_in tmp;
      socklen_t len = sizeof(tmp);
      int n = recvfrom(client->_socket,str,sizeof(str) - 1,0,(struct sockaddr*)&tmp,&len);//recvfrom是接收，这里的tmp是用来明确谁发给我的
      if(n != 0)
        str[n] = '\0';
      else
        continue; 

      cout << str << endl;
    }
    return nullptr;
  }

  ~UdpClient()
  {
    c->join();
    p->join();
  }

private:
  int _socket;
  string _serverIp;
  uint16_t _serverPort;
  Thread* c;
  Thread* p;
};
